package net.towee.server.xmpp;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import net.towee.model.account.AccountData;
import net.towee.model.account.AccountIdentity;
import net.towee.model.account.ContactsContainer;
import net.towee.model.account.ContactsGroup;
import net.towee.server.CoreSettings;
import net.towee.server.persistence.AccountStore;
import net.towee.shared.exceptions.PersistenceException;

import org.apache.vysper.xmpp.addressing.Entity;
import org.apache.vysper.xmpp.addressing.EntityFormatException;
import org.apache.vysper.xmpp.addressing.EntityImpl;
import org.apache.vysper.xmpp.modules.roster.Roster;
import org.apache.vysper.xmpp.modules.roster.RosterException;
import org.apache.vysper.xmpp.modules.roster.RosterGroup;
import org.apache.vysper.xmpp.modules.roster.RosterItem;
import org.apache.vysper.xmpp.modules.roster.SubscriptionType;
import org.apache.vysper.xmpp.modules.roster.persistence.RosterManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Inject;
import com.google.inject.name.Named;

/**
 * Roster manager, wrapper to Towee model.
 * 
 * @author c58
 */
public class XmppRosterManager implements RosterManager {
	private static final Logger LOG = LoggerFactory.getLogger(XmppRosterManager.class);
	
	/**
	 * Towee Roster. Wrapper to account contacts.
	 * 
	 * @author c58
	 */
	public class ToweeRoster implements Roster {
		// Map of all contacts of given account
		private final Map<Entity, RosterItem> items = new LinkedHashMap<Entity, RosterItem>();
		
		public ToweeRoster(ContactsContainer contacts) {
			for(ContactsGroup g : contacts.getContactsGroupsList()) {
				// Create roster group item
				RosterGroup rg = new RosterGroup( g.getName() );
				
				for(AccountIdentity acc : g.getContactsList()) {
					try {
						// Create roster item
						RosterItem ri = new RosterItem(EntityImpl.parse( acc.getNickName()+"@"+domain ),
								SubscriptionType.BOTH);
						
						// Add it to group
						ri.setGroups(Arrays.asList(rg));
						ri.setName( acc.getFullName() );
						
						// Add to map
						items.put(ri.getJid(), ri);
					} catch (EntityFormatException e) {
						throw new RuntimeException();
					}
				}
			}
			
			LOG.info("Roster contains of "+items.size()+" items "+domain);
		}
		
		@Override
		public Iterator<RosterItem> iterator() {
			return items.values().iterator();
		}

		@Override
		public RosterItem getEntry(Entity contact) {
			return items.get( contact.getNode() );
		}
		
	}
	
	// Account store injection
	private final AccountStore accountStore;
	
	// Current towee domain
	private final String domain;
	
	@Inject
	public XmppRosterManager(AccountStore accountStore, @Named(CoreSettings.TOWEE_SERVER_DOMAIN) String domain) {
		this.accountStore = accountStore;
		this.domain = domain;
	}
	
	@Override
	public Roster retrieve(Entity jid) throws RosterException {
		LOG.info("Retriving roster by JID: "+jid.getFullQualifiedName()+" "+domain);
		
		try {
			AccountData acc = accountStore.getAccountByNickname(jid.getNode(), "contacts");
			return new ToweeRoster( acc.getContacts() );
		} catch (PersistenceException e) {
			LOG.error("Filed to get account with nickname: "+ jid.getNode());
			return null;
		}
	}

	@Override
	public void addContact(Entity jid, RosterItem rosterItem) throws RosterException {
	}

	@Override
	public RosterItem getContact(Entity jidUser, Entity jidContact) throws RosterException {
		LOG.info("Try to get contact by jid: "+jidContact.getFullQualifiedName());
		
		return retrieve(jidUser).getEntry(jidContact);
	}

	@Override
	public void removeContact(Entity jid, Entity jidContact) throws RosterException {
	}
	
}